#include "rls-packet.h"
#include "ns3/packet.h"
#include "ns3/address-utils.h"

namespace ns3
{
namespace sls
{

NS_OBJECT_ENSURE_REGISTERED (TypeHeader);

TypeHeader::TypeHeader (MessageType t = SLS_LOCATION_QUERY) :
  m_type (t), m_valid (true)
{
}

TypeId
TypeHeader::GetTypeId ()
{
  static TypeId tid = TypeId ("ns3::rls::TypeHeader")
      .SetParent<Header> ()
      .AddConstructor<TypeHeader> ()
      ;
  return tid;
}

TypeId
TypeHeader::GetInstanceTypeId () const
{
  return GetTypeId ();
}

uint32_t
TypeHeader::GetSerializedSize () const
{
  return 1;
}

void
TypeHeader::Serialize (Buffer::Iterator i) const
{
  i.WriteU8 ((uint8_t) m_type);
}

uint32_t
TypeHeader::Deserialize (Buffer::Iterator start)
{
  Buffer::Iterator i = start;
  uint8_t type = i.ReadU8 ();
  m_valid = true;
  switch (type)
    {
    case SLS_LOCATION_QUERY:
    case SLS_LOCATION_REPLY:
      {
        m_type = (MessageType) type;
        break;
      }
    default:
      m_valid = false;
    }
  uint32_t dist = i.GetDistanceFrom (start);
  NS_ASSERT (dist == GetSerializedSize ());
  return dist;
}

void
TypeHeader::Print (std::ostream &os) const
{
  switch (m_type)
    {
    case SLS_LOCATION_QUERY:
      {
        os << "LOCATION_QUERY";
        break;
      }
    case SLS_LOCATION_REPLY:
      {
        os << "LOCAION_REPLY";
        break;
      }
    default:
      os << "UNKNOWN_TYPE";
    }
}

bool
TypeHeader::operator== (TypeHeader const & o) const
{
  return (m_type == o.m_type && m_valid == o.m_valid);
}

std::ostream &
operator<< (std::ostream & os, TypeHeader const & h)
{
  h.Print (os);
  return os;
}

LocQueryHeader::LocQueryHeader(Ipv4Address nodeIdDst, Vector nodePosSrc, 
							   Ipv4Address nodeIdSrc, uint32_t seqNumber, uint8_t ttl) :
							   m_nodeIdDst(nodeIdDst), m_nodePosSrc(nodePosSrc), m_nodeIdSrc(nodeIdSrc),
							   m_seqNumber(seqNumber), m_ttl(ttl) {}



NS_OBJECT_ENSURE_REGISTERED (LocQueryHeader);

TypeId
LocQueryHeader::GetTypeId ()
{
  static TypeId tid = TypeId ("ns3::rls::LocQueryHeader")
      .SetParent<Header> ()
      .AddConstructor<LocQueryHeader> ()
      ;
  return tid;
}

TypeId
LocQueryHeader::GetInstanceTypeId () const
{
  return GetTypeId ();
}

uint32_t
LocQueryHeader::GetSerializedSize () const
{
  return 21;
}

void
LocQueryHeader::Serialize (Buffer::Iterator i) const
{
  i.WriteU8 (m_ttl);
  i.WriteHtonU32 (m_seqNumber);
  i.WriteHtonU32((uint32_t) m_nodePosSrc.x);
  i.WriteHtonU32((uint32_t) m_nodePosSrc.y);
  WriteTo (i, m_nodeIdDst);
  WriteTo (i, m_nodeIdSrc);
  
}

uint32_t
LocQueryHeader::Deserialize (Buffer::Iterator start)
{
  Buffer::Iterator i = start;
  m_ttl = i.ReadU8 ();
  m_seqNumber = i.ReadNtohU32 ();
  m_nodePosSrc.x = i.ReadU8();
  m_nodePosSrc.y = i.ReadU8();
  ReadFrom (i, m_nodeIdDst);
  ReadFrom (i, m_nodeIdSrc);

  uint32_t dist = i.GetDistanceFrom (start);
  NS_ASSERT (dist == GetSerializedSize ());
  return dist;
}

void
LocQueryHeader::Print (std::ostream &os) const
{
  os << "Destination: ipv4 " << m_nodeIdDst << ", source: ipv4 " << m_nodeIdSrc << ", message sequence number"
	 << m_seqNumber << ", source position " << m_nodePosSrc << ", time to live " << m_ttl;
}

bool
LocQueryHeader::operator== (LocQueryHeader const & o) const
{
  return (m_nodeIdDst == o.m_nodeIdDst && m_nodePosSrc.x == o.m_nodePosSrc.x && m_nodePosSrc.y == o.m_nodePosSrc.y &&
          m_nodeIdSrc == o.m_nodeIdSrc && m_seqNumber == o.m_seqNumber && m_ttl == o.m_ttl);
}

std::ostream &
operator<< (std::ostream & os, LocQueryHeader const & h)
{
  h.Print (os);
  return os;
}

LocReplyHeader::LocReplyHeader(Ipv4Address nodeIdDst, Vector nodePosSrc, 
							   Vector nodePosDst, Ipv4Address nodeIdSrc,
							   uint32_t seqNumber, uint8_t ttl) :
							   m_nodeIdDst(nodeIdDst), m_nodePosSrc(nodePosSrc), m_nodePosDst(nodePosDst),
							   m_nodeIdSrc(nodeIdSrc), m_seqNumber(seqNumber), m_ttl(ttl) {}
NS_OBJECT_ENSURE_REGISTERED (LocReplyHeader);

TypeId
LocReplyHeader::GetTypeId ()
{
  static TypeId tid = TypeId ("ns3::sls::LocReplyHeader")
      .SetParent<Header> ()
      .AddConstructor<LocReplyHeader> ()
      ;
  return tid;
}

TypeId
LocReplyHeader::GetInstanceTypeId () const
{
  return GetTypeId ();
}

uint32_t
LocReplyHeader::GetSerializedSize () const
{
  return 29;
}

void
LocReplyHeader::Serialize (Buffer::Iterator i) const
{
  i.WriteU8 (m_ttl);
  i.WriteHtonU32 (m_seqNumber);
  i.WriteHtonU32(m_nodePosSrc.x);
  i.WriteHtonU32(m_nodePosSrc.y);
  i.WriteHtonU32(m_nodePosDst.x);
  i.WriteHtonU32(m_nodePosDst.y);
  WriteTo (i, m_nodeIdDst);
  WriteTo (i, m_nodeIdSrc);
  
}

uint32_t
LocReplyHeader::Deserialize (Buffer::Iterator start)
{
  Buffer::Iterator i = start;
  m_ttl = i.ReadU8 ();
  m_seqNumber = i.ReadNtohU32 ();
  m_nodePosSrc.x = i.ReadU8();
  m_nodePosSrc.y = i.ReadU8();
  m_nodePosDst.x = i.ReadU8();
  m_nodePosDst.y = i.ReadU8();
  ReadFrom (i, m_nodeIdDst);
  ReadFrom (i, m_nodeIdSrc);

  uint32_t dist = i.GetDistanceFrom (start);
  NS_ASSERT (dist == GetSerializedSize ());
  return dist;
}

void
LocReplyHeader::Print (std::ostream &os) const
{
  os << "Destination: ipv4 " << m_nodeIdDst << ", source: ipv4 " << m_nodeIdSrc << ", message sequence number"
	 << m_seqNumber << ", source position " << m_nodePosSrc << "destination position " << m_nodePosSrc << ", time to live " << m_ttl;
}

bool
LocReplyHeader::operator== (LocReplyHeader const & o) const
{
  return (m_nodeIdDst == o.m_nodeIdDst && m_nodePosSrc.x == o.m_nodePosSrc.x && m_nodePosSrc.y == o.m_nodePosSrc.y &&
		  m_nodeIdSrc == o.m_nodeIdSrc && m_seqNumber == o.m_seqNumber && m_ttl == o.m_ttl &&
		  m_nodePosDst.x == o.m_nodePosSrc.x && m_nodePosDst.y == o.m_nodePosSrc.y);
}

std::ostream &
operator<< (std::ostream & os, LocReplyHeader const & h)
{
  h.Print (os);
  return os;
}

}
}
